package cn.jasonone.jfx.manager;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.jasonone.jfx.context.BaseController;
import cn.jasonone.jfx.context.JFXContextHolder;
import cn.jasonone.jfx.controls.Controller;
import cn.jasonone.jfx.factory.StyleSheetInterceptor;
import cn.jasonone.jfx.mananger.BindManager;
import cn.jasonone.jfx.mananger.SceneManager;
import cn.jasonone.jfx.mananger.StageManager;
import cn.jasonone.jfx.mananger.aware.BindManagerAware;
import cn.jasonone.jfx.mananger.aware.FxmlManagerAware;
import cn.jasonone.jfx.mananger.aware.SceneManagerAware;
import cn.jasonone.jfx.mananger.aware.StageManagerAware;
import cn.jasonone.jfx.mananger.FxmlManager;
import cn.jasonone.jfx.model.ControllerDefinition;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author xujie
 * @version 1.0
 * @date 2021/12/21 9:59
 */
@Slf4j
@Data
@Component("fxmlManager")
public class JfxFxmlManager implements FxmlManager {
    private Marker M = MarkerFactory.getMarker("JFX FxmlManager");
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private JFXContextHolder contextHolder;
    @Resource
    private BindManager bindManager;
    private SceneManager sceneManager;
    private StageManager stageManager;

    /**
     * 根据控制器类型加载FXML
     *
     * @param <P>
     * @param controllerType
     * @return
     * @throws IOException
     */
    @Override
    public <P extends Parent> P loadPane(Class controllerType) throws IOException {
        log.debug(M, "加载控制器: {}", controllerType);
        ControllerDefinition controllerDefinition = contextHolder.getControllerDefinition(controllerType);
        Object controller = applicationContext.getBean(controllerDefinition.getType());
        FXMLLoader loader = new FXMLLoader(controllerDefinition.getFxmlPath(), controllerDefinition.getResourceBundle());
        Assert.notNull(controller, "在IOC容器中未找到指定的控制器:{}", controllerType);
        //region 控制器扩展点注入
        {
            if (controller instanceof BindManagerAware) {
                ((BindManagerAware) controller).setBindManager(bindManager);
            } else if (controller instanceof FxmlManagerAware) {
                ((FxmlManagerAware) controller).setFxmlManager(this);
            } else if (controller instanceof SceneManagerAware) {
                ((SceneManagerAware) controller).setSceneManager(sceneManager);
            } else if (controller instanceof StageManagerAware) {
                ((StageManagerAware) controller).setStageManager(stageManager);
            }
        }
        //endregion
        loader.setControllerFactory(type -> controller);
        P rootPane = null;
        try {
            log.debug(M, "加载FXML文件: {}", controllerDefinition.getFxmlPath());
            rootPane = loader.load();
        } catch (IllegalStateException e) {
            log.error(null, "Fxml文件[{}]加载失败", controllerDefinition.getFxmlPath(), e);
            throw e;
        }
        if (CollectionUtil.isNotEmpty(controllerDefinition.getStylesheets())) {
            log.debug(M, "加载样式文件: {}", controllerDefinition.getStylesheets());
            rootPane.getStylesheets().addAll(controllerDefinition.getStylesheets());
        }
        // 执行样式拦截器
        List<StyleSheetInterceptor> styleSheetInterceptors = contextHolder.getStyleSheetInterceptors();
        for (StyleSheetInterceptor styleSheetInterceptor : styleSheetInterceptors) {
            if (styleSheetInterceptor.isEnabled(null, null, rootPane)) {
                log.debug(M, "执行样式拦截器: {}", styleSheetInterceptor);
                styleSheetInterceptor.handler(rootPane.getStylesheets());
            }
        }
        // 将节点与处理器绑定
        contextHolder.bindController(rootPane, controller);
        if (controller instanceof BaseController) {
            log.debug(M, "绑定根节点到控制器: {}=>{}", rootPane, controller);
            // 将节点注入到处理器中
            ReflectUtil.setFieldValue(controller, "rootPane", rootPane);
            // 调用处理器的初始化方法
            log.debug(M, "调用控制器的初始化方法: {}#initialize", controller);
            ((BaseController) controller).initialize();
        }

        // 处理Controller标签
        log.debug(M, "处理当前视图中包含的子控制器: {}", controllerDefinition.getFxmlPath());
        Set<Controller> controllers = getControllers(rootPane);
        if (!controllers.isEmpty()) {
            for (Controller node : controllers) {
                Controller control = (Controller) node;
                try {
                    log.debug(M, "处理子控制器: {}=>", controllerDefinition.getFxmlPath(), control);
                    String controllerClassName = control.getController();
                    Class<Object> controlType = ClassUtil.loadClass(controllerClassName);
                    Parent parent = loadPane(controlType);
                    control.render(parent);
                } catch (IOException e) {
                    e.printStackTrace();
                    //control
                    log.error(null, "<Controller controller=\"{}\">标签初渲染失败", control.getController(), e);
                }
            }
        }
        return rootPane;
    }

    private Set<Controller> getControllers(Node rootPane) {
        Set<Node> nodes = rootPane.lookupAll("*");
        Set<Controller> controllers = new HashSet<>();
        if (nodes != null) {
            for (Node node : nodes) {
                if (node instanceof Controller) {
                    controllers.add((Controller) node);
                } else if (node != rootPane) {
                    controllers.addAll(getControllers(node));
                }
            }
        }
        return controllers;
    }


}
